package com.yungam.imcs.controller.dashboard;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yungam.common.bean.equip.EquipStableScore;
import com.yungam.common.bean.equip.Equipment;
import com.yungam.common.bean.hand_inspect.ProductInspectionHand;
import com.yungam.common.bean.process.ProductProcess;
import com.yungam.common.bean.process.ProductionProcess;
import com.yungam.common.bean.product.ProductionProduct;
import com.yungam.common.response.RetDTO;
import com.yungam.common.service.*;
import com.yungam.common.utils.DateUtils;
import com.yungam.imcs.utils.ProductUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Api(tags = "首页接口")
@RestController
@RequestMapping("/dashboard")
public class DashboardController {
    /**
     * 设备稳定性统计的设备
     */
    private final static Integer[] EQU_IDS = {90020, 90021, 90050, 90070, 90071, 90090, 90091};

    @Resource
    private DateUtils dateUtils;
    @Resource
    private ProductUtils productUtils;
    @Resource
    private ProductInspectionHandService productInspectionHandService;
    @Resource
    private ProductProcessService productProcessService;
    @Resource
    private ProductionProcessService productionProcessService;
    @Resource
    private EquipStableScoreService equipStableScoreService;
    @Resource
    private EquipmentService equipmentService;

    @ApiOperation("质量检验良品率信息")
    @GetMapping("/inspection")
    public RetDTO<?> getInspections() {
        List<ProductInspectionHand> all, yesterdayList, nowList;
        Integer lastOfNullStateCnt, nowOfNullStateCnt;
        String start, end;
        // 所有的质量检验信息 (排除 state 为 null)
        all = productInspectionHandService.list(
                new QueryWrapper<ProductInspectionHand>().isNotNull("state"));
        // 昨日信息
        String[] yr = dateUtils.getYesterdayRange();
        start = yr[0]; end = yr[1];
        yesterdayList = productInspectionHandService.list(
                new QueryWrapper<ProductInspectionHand>().isNotNull("state").between("create_time", start, end));
        lastOfNullStateCnt = productInspectionHandService.count(new QueryWrapper<ProductInspectionHand>()
                .between("create_time", start, end));
        // 今日信息
        String[] tr = dateUtils.getTodayRange();
        start = tr[0]; end = tr[1];
        nowList = productInspectionHandService.list(
                new QueryWrapper<ProductInspectionHand>().isNotNull("state").between("create_time", start, end));
        nowOfNullStateCnt = productInspectionHandService.count(new QueryWrapper<ProductInspectionHand>()
                .between("create_time", start, end));

        int good = 0;
        int[] percent = new int[2];
        // 历史良品率 & 昨日良品率
        for (ProductInspectionHand pih : all) if (pih.getState() == 1) good++;
        percent[1] = all.size() == 0 ? 0 : (int) Math.ceil((double) good / all.size() * 100);

        good = 0;
        for (ProductInspectionHand pih : yesterdayList) if (pih.getState() == 1) good++;
        percent[0] = yesterdayList.size() == 0 ? 0 : (int) Math.ceil((double) good / yesterdayList.size() * 100);

        // 今日良品信息
        int nowAll = nowList.size(), nowGood = 0, nowBad = 0;
        if (nowAll != 0) {
            for (ProductInspectionHand pih : nowList) if (pih.getState() == 1) nowGood++;
            nowBad = nowAll - nowGood;
        }
        Map<String, Object> ans = Maps.newHashMap();

        int lastAll = yesterdayList.size(), lastGood = good, lastBad = lastAll - lastGood;

        Map<String, List<Integer>> statData = Maps.newHashMap();
        // 今日生产的数量 包含 state == null 的情况
        statData.put("last", Lists.newArrayList(lastOfNullStateCnt, lastGood, lastBad));
        statData.put("now", Lists.newArrayList(nowOfNullStateCnt, nowGood, nowBad));

        ans.put("statData", statData);
        ans.put("chartData", percent);
        return RetDTO.data(ans);
    }

    /*
    * 每天平均周期时间 = 今日所有罐子包含的所有工序的耗时总和 / 今日所有罐子的总数
    *
    * */
    @ApiOperation("产线及物流周期耗时分析")
    @GetMapping("/timeAnalysisData")
    public RetDTO<?> getTimeAnalysisData() {
        LocalDateTime now = LocalDateTime.now(); // 当前时间
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        // 获取每日完成的罐号
        Map<String, List<ProductionProduct>> finishedMap = Maps.newHashMap();
        for (int i = 0; i < 7; i++) {
            LocalDateTime cur = now.minusDays(i);
            List<ProductionProduct> list = productUtils.getFinishedProductByDate(cur);
            String date = df.format(cur);
            finishedMap.put(date, list);
        }

        // 计算每天的平均周期耗时
        Map<String, Double> lineTimeMap = Maps.newHashMap();
        for (String s : finishedMap.keySet()) {
            List<ProductionProduct> list = finishedMap.getOrDefault(s, Lists.newArrayList());
            if (list.size() == 0) {
                lineTimeMap.put(s, 0d);
                continue;
            }
            List<String> snList = list.stream()
                                        .map(ProductionProduct::getProductSn)
                                        .collect(Collectors.toList());
            List<ProductionProcess> processes = productionProcessService.list(new QueryWrapper<ProductionProcess>()
                    .in("product_sn", snList));
            double avg = lineCalculate(processes);
            lineTimeMap.put(s, avg);
        }

        // 计算每天的平均物流周期耗时
        Map<String, Double> agvTimeMap = Maps.newHashMap();
        for (String s : finishedMap.keySet()) {
            List<ProductionProduct> list = finishedMap.getOrDefault(s, Lists.newArrayList());
            if (list.size() == 0) {
                agvTimeMap.put(s, 0d);
                continue;
            }
            long agvSum = 0;
            double n = list.size();
            for (ProductionProduct pp : list) {
                String productNo = pp.getProductNo(), productSn = pp.getProductSn();
                agvSum += agvCalculate(productSn, productNo);
            }
            // 转成小时
            double hours = agvSum / (double) (1000 * 60 * 60);
            double avg = Double.parseDouble(String.format("%.3f", hours / n));
            agvTimeMap.put(s, avg);
        }

        // 按照时间顺序整理数据
        List<Double> lineTimeList = Lists.newArrayList(),
                        agvTimeList = Lists.newArrayList();
        List<String> dateList = Lists.newArrayList();
        for (int i = 6; i >= 0; i--) {
            LocalDateTime cur = now.minusDays(i);
            String date = df.format(cur);
            dateList.add(date);
            lineTimeList.add(lineTimeMap.get(date));
            agvTimeList.add(agvTimeMap.get(date));
        }
        Map<String, Object> ans = Maps.newHashMap();
        ans.put("line", lineTimeList);
        ans.put("agv", agvTimeList);
        ans.put("date", dateList);
        return RetDTO.data(ans);
    }

    /* 计算产线平均耗时 */
    private Double lineCalculate(List<ProductionProcess> processes) {

        int len = processes.size();
        if (len == 0) return 0d;

        double n = len;
        long sum = 0;
        for (ProductionProcess pp : processes) {
            Date start = pp.getStartTime(), end = pp.getEndTime();
            if (start == null || end == null) continue;
            long diff = end.getTime() - start.getTime();
            if (diff < 0) continue;
            sum += diff;
        }

        // 转成小时
        double hours = sum / (double) (1000 * 60 * 60);

        return Double.parseDouble(String.format("%.3f", hours / n));
    }

    /* 计算物流平均耗时 */
    private Long agvCalculate(String productSn, String productNo) {

        // 获取该产品的所有工序
        List<ProductProcess> processes = productProcessService.list(new QueryWrapper<ProductProcess>()
                .eq("product_no", productNo).orderByAsc("process_id"));
        List<String> processNos = processes.stream().map(ProductProcess::getProcessNo).collect(Collectors.toList());

        // 将前后工序存入 Map, 最后一道工序无物流耗时
        Map<String, String> linkedProcess = Maps.newHashMap();
        int length = processNos.size();
        for (int i = 0; i < length; i++) {
            if (i == length - 1) {
                linkedProcess.put(processNos.get(i), null); // 最后一道工序
                break;
            }
            String cur = processNos.get(i), after = processNos.get(i + 1);
            linkedProcess.put(cur, after);
        }

        // 根据罐号查询所有的 productionProcess
        List<ProductionProcess> list = productionProcessService.list(new QueryWrapper<ProductionProcess>()
                .eq("product_sn", productSn));
        // 将所有工序的开始时间存入 Map
        Map<String, Date> startMap = Maps.newHashMap();
        for (ProductionProcess pp : list) startMap.put(pp.getProcessNo(), pp.getStartTime());

        long sum = 0; // 该罐子的总物流耗时
        for (ProductionProcess pp : list) {
            String next = linkedProcess.get(pp.getProcessNo());
            if (next == null) continue;
            Date start = pp.getEndTime(), end = startMap.get(next);
            if (start == null || end == null) continue;
            long diff = end.getTime() - start.getTime();
            if (diff < 0) continue;
            sum += diff;
        }

        return sum;
    }

    @ApiOperation("设备稳定性周平均得分")
    @GetMapping("/stableScores")
    public RetDTO<?> getStableScores() {
        ZoneId zid = ZoneId.systemDefault();
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd"),
        df2 = DateTimeFormatter.ofPattern("MM-dd");
        LocalDateTime now = LocalDateTime.now();
        // 获取过去7天的所有数据
        LocalDateTime lastWeek = now.minusDays(6);
        String start = lastWeek.format(df), end = now.format(df);
        start += " 00:00:00"; end += " 23:59:59";
        List<EquipStableScore> dataList = equipStableScoreService.list(new QueryWrapper<EquipStableScore>()
                .between("create_time", start, end));
        // 按照`日期-设备ID`的格式存入Map
        Map<String, List<EquipStableScore>> map = Maps.newHashMap();
        for (EquipStableScore es : dataList) {
            String dateStr = LocalDateTime.ofInstant(
                    es.getCreateTime().toInstant(), zid).format(df2);
            String key = dateStr + "-" + es.getEquId();
            List<EquipStableScore> od = map.getOrDefault(key, Lists.newArrayList());
            od.add(es);
            map.put(key, od);
        }
        // 计算每天每个设备的平均得分
        Map<Integer, List<Integer>> scoreOfEquip = Maps.newHashMap();
        for (Integer equId : EQU_IDS) {
            for (int i = 6; i >= 0; i--) {
                String dateStr = now.minusDays(i).format(df2);
                String key = dateStr + "-" + equId;
                List<EquipStableScore> equList = map.getOrDefault(key, Lists.newArrayList());
                int avgScore = 0;
                if (equList.size() > 0) {
                    int sum = equList.stream().map(EquipStableScore::getScore).reduce((x, y) -> x + y).orElse(0);
                    avgScore = sum / equList.size();
                    if (avgScore > 100) avgScore = 99;
                }
                List<Integer> scoreList = scoreOfEquip.getOrDefault(equId, Lists.newArrayList());
                scoreList.add(avgScore);
                scoreOfEquip.put(equId, scoreList);
            }
        }
        // 获取7个设备对应的名称
        Map<Integer, String> equipInfos = Maps.newHashMap();
        QueryWrapper<Equipment> queryWrapper = new QueryWrapper<>();
        queryWrapper.select(Equipment.class, col -> !col.getProperty().equals("equImg"))
                .in("equ_id", EQU_IDS);
        List<Equipment> equipList = equipmentService.list(queryWrapper);
        for (Equipment equip : equipList) equipInfos.put(equip.getEquId(), equip.getEquName());

        // 整合数据
        Map<String, Object> ans = Maps.newHashMap();
        List<Map<String, Object>> stableData = Lists.newArrayList();
        for (Integer equId : EQU_IDS) {
            Map<String, Object> item = Maps.newHashMap();
            List<Integer> scores = scoreOfEquip.getOrDefault(equId, Lists.newArrayList(0, 0, 0, 0, 0, 0, 0));
            item.put("equId", equId);
            item.put("data", scores);
            item.put("name", equipInfos.getOrDefault(equId, ""));
            stableData.add(item);
        }
        ans.put("yData", stableData);
        List<String> xData = Lists.newArrayList();
        for (int i = 6; i >= 0; i--) {
            String dateStr = now.minusDays(i).format(df2);
            xData.add(dateStr);
        }
        ans.put("xData", xData);
        return RetDTO.data(ans);
    }

}
